package com.tmc.util;

import java.io.UnsupportedEncodingException;

/**
 * base64编码与解码
 * @author jazz young
 *
 */
public class Base64Util {
	//base64位码表
	public static final char[] base64={'A','B','C','D','E','F','G','H',
		                               'I','J','K','L','M','N','O','P',
		                               'Q','R','S','T','U','V','W','X',
		                               'Y','Z','a','b','c','d','e','f',
		                               'g','h','i','j','k','l','m','n',
		                               'o','p','q','r','s','t','u','v',
		                               'w','x','y','z','0','1','2','3',
		                               '4','5','6','7','8','9','+','/'};
	//二进制表示
	public static int[] hex2={0,0,0,0,0,0,0,0};
	
	/**
	 * base64编码
	 * @param bts
	 * @return byte[]
	 */
	public static byte[] encode(byte[] bts){
		return encodeAsString(bts).getBytes();
	}
	
	/**
	 * base64编码
	 * @param bts
	 * @return string
	 */
	public static String encodeAsString(byte[] bts){
		StringBuffer sb =new StringBuffer();
		String res ="";
		int btsRec = (bts.length-1)/3+1;
		for (int i = 0; i < btsRec; i++) {
			int[][] mix =new int[3][8]; 
			for (int j = i*3; j < (i+1)*3; j++) {
				if(j>=bts.length){
					mix[j%3]=hex2;
					continue;
				}
				mix[j%3]= numToHex2(bts[j]);
			}
			int[][] arr48 = array38ToArray48(mix);
			for (int j = 0; j < arr48.length; j++) {
				res = sb.append(base64[hex2ToNum(arr48[j])]).toString();
			}
			
		}
		//判断最后3个字节缺2个输出2个=
		if(bts.length %3 ==1 ){
			res =res.substring(0,res.length()-2)+"==";
		}
		//判断最后3个字节缺1个输出1个=
		if(bts.length %3 ==2){
			res =res.substring(0,res.length()-1)+"=";
		}
		return res;
	}
	
	/**
	 * base64解码
	 * @param bts
	 * @return
	 */
	public static byte[] decode(byte[] bts){
		try {
			String str =new String(bts,"UTF-8");
			return decode(str);
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
			return null;
		}
		
	}
	
	/**
	 * base64解码
	 * @param str
	 * @return
	 */
	public static byte[] decode(String str){
		String baseStr = String.valueOf(base64);
		char[] chs = str.toCharArray();
		int rec = chs.length/4;
		//定义数组数据承载运算结果
		byte[] bts =new byte[3*rec];
		//定义数组数据承载输出结果
		byte[] outs =null; 
		int index =0;
		for (int i = 0; i < rec; i++) {
			int[][] arr48 =new int[4][8];
			int count =0;
			for (int j = i*4; j < (i+1)*4; j++) {
				//从base64码表反检出对应下标
				//判断末尾是否有等号
				if(str.endsWith("==") && i==rec-1 && j>=4*i+2 &&j<=4*i+3){
					arr48[count] = numToHex2(baseStr.indexOf('A'));
				}else if(!str.endsWith("==") && str.endsWith("=") && i==rec-1 && j==4*i+3){
					arr48[count] = numToHex2(baseStr.indexOf('A'));
				}else{
				    arr48[count] = numToHex2(baseStr.indexOf(chs[j]));
				}
				count++; 
			}
			int[][] arr38 = array48ToArray38(arr48);
			for (int j = 0; j < arr38.length; j++) {
				bts[index] =(byte)hex2ToNum(arr38[j]);
				index++;
			}
		}
		
		//判断末尾是否有等号"=="
		if(str.endsWith("==")){
			outs =new byte[bts.length-2];
			for (int i = 0; i < bts.length-2; i++) {
				outs[i]=bts[i];
			}
		}//判断末尾是否有等号"=="
		else if(!str.endsWith("==")&&str.endsWith("=")){
			outs =new byte[bts.length-1];
			for (int i = 0; i < bts.length-1; i++) {
				outs[i]=bts[i];
			}
		}else{
			outs =new byte[bts.length];
			outs=bts;
		}
		return outs;
	}
	
	
	/**
	 * 十进制转二进制
	 * @param num
	 * @return
	 */
	public static int[] numToHex2(int num){
		int[] records ={0,0,0,0,0,0,0,0};
		int[] outs={0,0,0,0,0,0,0,0};
		int count = 0;
		while(num!=0){
			int num2= num%2;
		    num= num/2;
		    records[count]=num2;
		    count++;
		} 
		
		int j=0;
		for(int i=7;i>=0;i--){
			outs[j]=records[i];
			j++;
		}
		return outs;
	}
	
	/**
	 * 二进制转十进制
	 * @param nums
	 * @return
	 */
	public static int hex2ToNum(int[] nums){
		int sum =0;
		int j=8;
		for (int i = 0; i < nums.length; i++) {
			sum += nums[i]*new Double(Math.pow(2,j-1)).intValue();
			j--;
		}
		return sum;
	}
	
	/**
	 * 3个8位字节转4个8位
	 * @param num38
	 * @return
	 */
	public static int[][] array38ToArray48(int[][] num38){
		
		int[] num24 = new int[24];
		int[][] num48 =new int[4][8];
		for (int i = 0; i < num38.length; i++) {
			for (int j = 0; j < num38[i].length; j++) {
				num24[i*num38[i].length+j]=num38[i][j];
			}
		}
		
		for (int i = 0; i < num48.length; i++) {
			int count02=0;
			for (int j = 0; j < num48[i].length; j++) {
				if(j>=0&&j<=1){
					num48[i][j]=0;
				}else{
					num48[i][j]=num24[i*6+count02];
					count02++;
				}
			}
		}
		return num48;
	}
	
	/**
	 * 4个8位字节转3个8位
	 * @param num48
	 * @return
	 */
	public static int[][] array48ToArray38(int[][] num48){
		int[] num24 =new int[24];
		int[][] num38 =new int[3][8];
		int count01 = 0;
		for (int i = 0; i < num48.length; i++) {
			for (int j = 0; j < num48[i].length; j++) {
				if(j==0||j==1){
					continue;
				}
				num24[count01] = num48[i][j];
				count01++;
			}
		}
		
		for (int i = 0; i < num38.length; i++) {
			for (int j = 0; j < num38[i].length; j++) {
				num38[i][j] = num24[i*num38[i].length+j];
			}
		}
		return num38;
	}
	
	//测试
	public static void main(String[] args) {
		
		//int[] outs =numToHex2(4);
		//int num = hex2ToNum(outs);
		/*String str ="122222";
		try {
			String out =encodeAsString(str.getBytes("UTF-8"));
			System.out.println(out);
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}*/
		//System.out.println(String.valueOf(base64).indexOf("M"));
		
		
		/**
		 * MTIyMzRkZnNkZnNm
		 * MTIyMzRkZnNkZnNm
		 * 
		 * MTIyMzRkZnNkZnMx
		 * MTIyMzRkZnNkZnMx
		 * 
		 * MTIyMzRkZnNkZnM=
		 * MTIyMzRkZnNkZnM=
		 */
		
		String str ="12234dfsdfs";
		byte[] bts1 =str.getBytes();
		String out = encodeAsString(bts1);
		//System.out.println(out);
		
		byte[] bts2 = decode(out);
		for (int i = 0; i < bts2.length; i++) {
			System.out.print((char)bts2[i]);
		}
	}
	
}
